﻿/*

Copyright (c) 2012 Lucas Agudiez (Agu10)

Online Math Calculator is released under the MIT license.
See the file license.txt for copying permission.





 */




using System;
using System.Collections.Generic;
using System.Web;
using WrapperCore;

public class MathOnlineConverter
{
    const string AppID = "Y3575L-YGXQ4893JA"; // This is our App ID required to interface with wolfram alpha

    static List<string> acceptedVariables() // this returns a list of accepted constants for wolfram alpha: from a to z, without x, y, e, and i since x and y are variables, not constants, and e and i are numbers.
    {
        List<string> answer = new List<string>();
        for (int i = 0; i < 26; i++)
        {
            string v = ""+(char)((int)'a' + i);
            answer.Add(v);
        }
        answer.Remove("x");
        answer.Remove("y");
        answer.Remove("e");
        answer.Remove("i");
        return answer;
    }
    static bool isLetter(char c) // checks if this character is a letter a to z and A to Z
    {
        int code = (int)c;
        if (code >= (int)'a' && code <= (int)'z')
        {
            return true;
        }
        if (code >= (int)'A' && code <= (int)'Z')
        {
            return true;
        }
        return false;
    }
    static bool isNumber(char c) // check if this character is a number 0 to 9
    {
        int code = (int)c;
        if (code >= (int)'0' && code <= (int)'9')
        {
            return true;
        }
        return false;
    }

    Dictionary<string, string> replace = new Dictionary<string, string>(); // saves the information of what has to be replaced in the query and answer

    List<string> constants = new List<string>();
    public  List<string> Constants
    {
        get
        {
            return new List<string>(constants);
        }
        set
        {
            // When setting the constants list, we fill the dictionary so we know what to replace them with.
            
            constants.Clear();
            if (constants != null)
            {
                constants.AddRange(value);

                List<string> acceptedVars = acceptedVariables();
                int acceptedVarIndex = 0;

                replace.Clear();

                foreach (string constant in constants)
                {
                    if (!replace.ContainsKey(constant))
                    {
                        replace.Add(constant, acceptedVars[acceptedVarIndex]);
                        acceptedVarIndex++;
                    }
                }
                if (acceptedVarIndex >= 23)
                {
                    throw new Exception("Too many vars!");
                }
            }
        }
    }
    string dependentVariable = "";
    public string DependentVariable
    {
        get
        {
            return dependentVariable;
        }
        set
        {
            dependentVariable = value;
        }
    }
    string independentVariable = "";
    public string IndependentVariable
    {
        get
        {
            return independentVariable;
        }
        set
        {
            independentVariable = value;
        }
    }

    public MathOnlineConverter(List<string> constants = null, string dependentVar = "", string independentVar = "")
    {
        Constants = constants;
        DependentVariable = dependentVar;
        IndependentVariable = independentVar;
    }

    public static List<string> FindConstants(string query) // This looks at the query and returns a list of possible constants that you're using...
    {
        List<string> constants = new List<string>();

        string word = "";
        for (int i = 0; i < query.Length; i++)
        {
            if (isLetter(query[i]))
            {
                word += query[i];
            }
            else
            {
                if (word != "")
                {
                    if (!constants.Contains(word))
                    {
                        constants.Add(word);
                    }
                }
                word = "";
            }
        }

        return constants;
    }

    public string ConvertQuery(string query) // We replace variables and constants in the query
    {

        if (DependentVariable != "")
        {
            query = query.Replace(DependentVariable, "y");
        }
        if (IndependentVariable != "")
        {
            query = query.Replace(IndependentVariable, "x");
        }
        foreach (string key in replace.Keys)
        {
            query = query.Replace(key, replace[key]);
        }
        return query;
    }
    string convertSpacesToAsteriscs(string answer) // For multiplication
    {
        char[] array = answer.ToCharArray();
        for (int i = 0; i < answer.Length; i++)
        {
            char current = array[i];
            char prev = '=';
            char next = '=';
            if(i-1>=0)
            {
                prev = array[i - 1];
            }
            if (i + 1 < array.Length)
            {
                next = array[i + 1];
            }
            if (current == ' ')
            {
                if ((isLetter(prev) || prev == '(' | prev == ')' || isNumber(prev)) &&
                    (isLetter(next) || next == '(' | next == ')' || isNumber(next)))
                {
                    array[i] = '*';
                }
            }
        }
        return new string(array);
    }

    static string replaceFromWolfram(string text, char oldValue, string newValue)
    {
        char[] array = text.ToCharArray();
        for (int i = 0; i < array.Length; i++)
        {
            char current = array[i];
            char prev = '=';
            char next = '=';
            if(i-1>=0)
            {
                prev = array[i - 1];
            }
            if (i + 1 < array.Length)
            {
                next = array[i + 1];
            }
            if (isLetter(current) && current == oldValue)
            {
                if (!isLetter(prev) && !isLetter(next))
                {
                    text = text.Substring(0, i) + newValue + text.Substring(i + 1);
                    array = text.ToCharArray();
                }
            }
        }
        return text;
    }

    public string ConvertSolution(string answer) // we convert our wolfram alpha answer back to the input format
    {
        answer = convertSpacesToAsteriscs(answer);

        if (DependentVariable != "")
        {
            //answer = answer.Replace("y", DependentVariable);
            answer = replaceFromWolfram(answer, 'y', DependentVariable);
        }
        if (IndependentVariable != "")
        {
            //answer = answer.Replace("x", IndependentVariable);
            answer = replaceFromWolfram(answer, 'x', IndependentVariable);
        }
        foreach (string key in replace.Keys)
        {
            //answer = answer.Replace(replace[key], key);
            answer = replaceFromWolfram(answer, replace[key][0], key);
        }
        return answer;
    }

    public string newSearch(string query) // just testing, this is not being used.
    {
        string result = "";

        WolframAlphaEngine engine = new WolframAlphaEngine(AppID);
        string request = engine.GetStringRequest(new WolframAlphaQuery() { Query = HttpUtility.UrlEncodeUnicode(query), APIKey = AppID });
        engine.GetWolframAlphaQueryResult(request);

        if (engine.QueryResult == null || engine.QueryResult.Error || engine.QueryResult.NumberOfPods == 0)
        {
            result += "<b>ERROR</b>";
            return result;
        }
        result += "<br/>";
        foreach (string key in replace.Keys)
        {
            result += "<b>" + replace[key] + "</b> = " + key + ", ";
        }
        result += " | " + query;
        
        result += "<br/><br/><br/><br/>";

        result += "<table><tr><td>";
        foreach(WolframAlphaPod pod in engine.QueryResult.Pods)
        {
            result += "<p><b>" + pod.Title +"</b></p>";
            foreach (WolframAlphaSubPod subPod in pod.SubPods)
            {
                result += "<p>" + ConvertSolution(subPod.PodText) + "</p>";
                result += "<p><img width=" + subPod.PodImage.Width + " height=" + subPod.PodImage.Height + " src='" + subPod.PodImage.Location.ToString() + "' alt='" + subPod.PodImage.HoverText + "' /></p>";
            }
        }
        result += "</td></tr></table>";
        return result;
    }


    public string Search(string query) // we search and return the results
    {
        string result = "";

        WolframAlphaEngine engine = new WolframAlphaEngine(AppID);
        string request = engine.GetStringRequest(new WolframAlphaQuery() { Query = HttpUtility.UrlEncodeUnicode(query), APIKey = AppID });
        engine.GetWolframAlphaQueryResult(request); // we have requested wolfram alpha for a result

        if (engine.QueryResult == null || engine.QueryResult.Error || engine.QueryResult.NumberOfPods == 0)
        {
            result += "<b>ERROR</b>";
            return result;
        }

        result += "<br/>";
        foreach (string key in replace.Keys)
        {
            result += "<b>" + replace[key] + "</b> = " + key + ", "; // We print every constant that we replaced.
        }
        result += " | " + query; // We print the converted query in wolfram alpha style.

        result += "<br/>";

        result += "<table><tr><td><ul>"; // We make a list
        foreach (WolframAlphaPod pod in engine.QueryResult.Pods) // A pod is like a different part of the answer
        {
            result += "<li>";
            result += "<b>" + pod.Title + "</b>"; // We print the title of this part
            result += "<ul>";
            foreach (WolframAlphaSubPod subPod in pod.SubPods) // Each part has different sub-parts
            {
                result += "<li>";
                result += "<p>" + ConvertSolution(subPod.PodText) + "</p>"; // We convert back to input format
                //result += "<img width=" + subPod.PodImage.Width + " height=" + subPod.PodImage.Height + " src='" + subPod.PodImage.Location.ToString() + "' alt='" + subPod.PodImage.HoverText + "' />";
                //result += "<img src='http" + "://shitalshah.com/?$" + ConvertSolution(subPod.PodText) + "$' />";
                result += "<img src='https" + "://chart.googleapis.com/chart?cht=tx&chs=20&chf=bg,s,FFFFFF00&chl=" + HttpUtility.UrlEncodeUnicode(ConvertSolution(subPod.PodText)) + "' />";
                result += "</li>"; // We also print the images
            }
            result += "</ul>";
            result += "</li>";
        }
        result += "</ul></td></tr></table>";
        return result;
    }
}
